# -*- coding: utf-8 -*-
import json
import os_package
from playwright.sync_api import sync_playwright
import ctypes
import time_package


class Playwright_Management():
    def __init__(self, mode=0, headless=False, cookies_is_ok=False, alert_default_ok=True, is_windows_max=True):
        # 选择引擎
        self.mode = mode
        # 是否无头
        self.headless = headless
        # 是否开启cookies
        self.cookies_is_ok = cookies_is_ok
        # 是否默认接受弹窗
        self.alert_default_ok = alert_default_ok
        # 是否窗口最大化
        self.is_windows_max = is_windows_max

        self.browser = None
        self.context = None
        self.os_opt = os_package.Os_Option()
        self.time_opt = time_package.Time_Option()
        self.cookies_path = f'file/{self.os_opt.get_current_file_name()[0]}_cookies.json'
        self.open_browser()

    def __del__(self):
        self.close()

    def close(self):
        if self.page:
            try:
                self.page.close()
            except Exception as e:
                pass
        if self.browser:
            try:
                self.browser.close()
            except Exception as e:
                pass
        if self.playwright:
            try:
                self.playwright.stop()
            except Exception as e:
                pass

    # 保存cookies
    def save_cookies(self):
        try:
            cookies = self.context.cookies()
            with open(self.cookies_path, 'w') as f:
                json.dump(cookies, f)
            return True
        except Exception as e:
            print(f'保存cookies失败：{e}')
            return False

    # 加载cookies
    def load_cookies(self):
        if self.os_opt.get_isexist(self.cookies_path):
            with open(self.cookies_path, 'r') as f:
                cookies = json.load(f)
            valid_cookies = []
            current_time = time_package.time.time()
            for cookie in cookies:
                if 'expires' in cookie and cookie['expires'] > 0 and cookie['expires'] < current_time:
                    continue
                if 'max - age' in cookie and cookie['max - age'] > 0 and (
                        current_time - cookie.get('creationDate', 0)) > \
                        cookie['max - age']:
                    continue
                valid_cookies.append(cookie)
            if not valid_cookies:
                print('所有Cookies均已失效！')
                return False

            self.context.add_cookies(valid_cookies)
            return True
        else:
            print('未获取到cookies！')
            return False

    # 打开浏览器
    def open_browser(self):
        # 使用 ctypes 获取屏幕尺寸
        user32 = ctypes.windll.user32
        screen_width = user32.GetSystemMetrics(0)
        screen_height = user32.GetSystemMetrics(1)
        viewport_size = {'width': screen_width, 'height': screen_height}
        # context = sele.browser.new_context(viewport=viewport_size)
        self.playwright = sync_playwright().start()
        # with sync_playwright() as playwright_p:
        if self.mode == 0:
            self.browser = self.playwright.chromium.launch(headless=self.headless,
                                                           args=['--start-maximized', '--incognito'],
                                                           downloads_path='download_files')
        elif self.mode == 1:
            self.browser = self.playwright.webkit.launch(headless=self.headless,
                                                         args=['--start-maximized', '--incognito'],
                                                         downloads_path='download_files')
        else:
            self.browser = self.playwright.firefox.launch(headless=self.headless,
                                                          args=['--start-maximized', '--incognito'],
                                                          downloads_path='download_files')

        # browser = playwright_p.chromium.launch(headless=is_gui)
        self.context = self.browser.new_context(viewport=viewport_size)
        # self.context = self.browser.new_context()
        self.page = self.context.new_page()
        self.page.wait_for_load_state('load')
        if self.alert_default_ok:
            self.page.on("dialog", lambda dialog: dialog.accept())
        else:
            self.page.on("dialog", lambda dialog: dialog.reject())
        self.page.goto('https://www.baidu.com')

    # 钉钉登陆
    def dingding_login(self, is_auto_click=False, select_organization=1):
        url = "https://login.dingtalk.com/oauth2/challenge.htm?spm=dd_developers.homepage.0.0.205a4a97lu7uJM&redirect_uri=https%3A%2F%2Fopen.dingtalk.com%2Fdingtalk_sso_call_back%3Fcontinue%3Dhttps%3A%2F%2Fopen.dingtalk.com%2F&response_type=code&client_id=dingbakuoyxavyp5ruxw&scope=openid+corpid"
        try:
            self.load_cookies()
            # todo 121122
            self.page.goto(url)

            # 判断是否出现登陆界面
            t = 60
            while True:
                # 选择组织
                if self.page.get_by_text("选择你加入的组织").is_visible(timeout=500):
                    if self.page.locator('.module-corp-sel-list .module-corp-sel-listitem').count() > 0:
                        # 默认选择第一个组织，如需更改，请在函数之中更改
                        self.page.locator('.module-corp-sel-list .module-corp-sel-listitem').nth(
                            select_organization - 1).click()
                        self.page.wait_for_timeout(timeout=3000)
                        break
                if self.page.get_by_text("继续使用开发者后台统一登录").nth(1).is_visible(timeout=500):
                    # 选择账号
                    self.page.wait_for_timeout(timeout=3000)
                    if self.page.locator('.module-qrcode-user-avatar-info').is_visible(timeout=500):
                        # print(self.page.url),
                        self.page.locator(f'.module-qrcode-user-avatar-info').click()
                        self.page.wait_for_timeout(timeout=3000)
                if t <= 0:
                    break
                t -= 1

            if t <= 0:
                return False
            self.save_cookies()
            return True

        except Exception as e:
            print(e)
            return False

    # educode登陆http://www.educode.cc
    def educode_login(self, zh=None, mm=None):
        # 检查是否过期
        def check_is_expired():
            if self.page.get_by_text("二维码已过期").is_visible():
                self.page.get_by_text("刷新").click()
                print('已自动刷新二维码！')
            return True

        # 检查是否出现登陆
        def check_is_denglu_button(t=3):
            t_t = t
            while t > 0:
                if self.page.get_by_text('确认登录').is_visible():
                    self.page.get_by_text('确认登录').click()
                    print('已自动点击【自动登录】！')
                if t_t <= 0:
                    break
                self.page.wait_for_timeout(timeout=1000)
                t_t -= 1
            if t_t <= 0:
                return False
            return True

        # 切换到班级
        def check_is_class(t=3):
            t_t = t
            # self.page.wait_for_timeout(timeout=4000)
            while t > 0:
                if self.page.get_by_role("link", name="班级", exact=True).is_visible():
                    self.page.get_by_role("link", name="班级", exact=True).click()
                    break
                if t_t <= 0:
                    break
                self.page.wait_for_timeout(timeout=1000)
                t_t -= 1
            if t_t <= 0:
                return False
            print('登录成功！')
            return True

        url = ('http://www.educode.cc')
        try:
            if zh is not None and mm is not None:
                self.page.goto(url)
                self.page.get_by_text("账号登录").click()
                self.page.get_by_placeholder("请输入你的帐号").fill(str(zh))
                self.page.get_by_placeholder("密码").fill(str(mm))
                self.page.get_by_role("link", name="登录").click()
                print(f'使用账号：{str(zh)}登陆{url}中...')
                check_is_denglu_button()
                if check_is_class():
                    return True
                else:
                    return False
            else:
                self.load_cookies()
                self.page.goto(url)
                # self.page.get_by_text("扫码登录").click()
                while True:
                    # cookies有效直接登陆
                    if check_is_class():
                        break
                    if check_is_denglu_button():
                        if check_is_class():
                            break
                    check_is_expired()
                    print(f'等待{url}登陆中...')
                # self.page.get_by_role("link", name="班级").click()
                self.save_cookies()
                return True

        except Exception as e:
            print(e)
            return False

    # 教学记录系统登陆http://tj.clound.xyz:5001/
    def teaching_record_system_login(self, zh, mm):
        def check_is_denglu(t=3):
            t_t = t
            while t > 0:
                if self.page.get_by_role("heading", name="仪表板").is_visible():
                    break
                if t_t <= 0:
                    break
                self.page.wait_for_timeout(timeout=1000)
                t_t -= 1
            if t_t <= 0:
                return False
            return True

        url = ('http://tj.clound.xyz:5001/')
        self.load_cookies()
        self.page.goto(url)
        if not check_is_denglu():
            # get_by_role("heading", name="仪表板")
            self.page.get_by_label("用户名").fill(str(zh))
            self.page.get_by_label("密码").fill(str(mm))
            self.page.get_by_role("button", name="登录").click()
            self.page.wait_for_timeout(timeout=3000)
            if check_is_denglu():
                # print(f'使用账号：{str(zh)}登陆{url}成功！')
                self.save_cookies()
                return True
            else:
                # print(f'登陆{url}失败，请检查账号{str(zh)}-密码{str(mm)}是否有误！')
                return False
        else:
            self.save_cookies()
            # print(f'使用cookies登陆{url}成功！')
            return True

    # 钉钉指定文件下载
    def dingding_file_download(self, goal_url, save_path):
        try:
            self.page.goto(url=goal_url)
            self.page.wait_for_timeout(2000)
            self.page.get_by_test_id("onlineEdit").click()
            # k.page.pause()
            with self.page.expect_popup() as page1_info:
                self.page.get_by_text("在线编辑原文件").click()
            # k.page.pause()
            self.page.wait_for_timeout(10000)
            page1 = page1_info.value
            page1.get_by_test_id("doc-header-more-button").click()
            # k.page.pause()
            page1.locator("div:nth-child(12) > .styled__Suffix-wdn__sc-5twhdd-4").hover()

            with page1.expect_download() as download_info:
                page1.get_by_text("Excel (.xlsx，表格整体)").click()
            download = download_info.value
            download.save_as(save_path)
            # print(f'已在线下载：{save_path}')
            return True
        except Exception as e:
            # print(f'下载失败：{e}')
            return False

    # 教学记录系统下载指定日期课时数据
    def teaching_record_system_course_data_download(self, start_date, end_date, save_path):
        '''
        教学记录系统下载指定日期课时数据
        :param start_date: 字符串开始日期，2025年3月1日
        :param end_date:
        :param save_path:
        :return:
        '''
        try:
            self.page.get_by_role("link", name=" 教学记录").click()
            self.page.get_by_placeholder("开始日期").click()
            self.page.get_by_placeholder("开始日期").fill(
                self.time_opt.timestamp_to_date(self.time_opt.date_str_to_timestamp(start_date)).strftime('%Y-%m-%d'))
            self.page.get_by_placeholder("结束日期").fill(
                self.time_opt.timestamp_to_date(self.time_opt.date_str_to_timestamp(end_date)).strftime('%Y-%m-%d'))
            self.page.get_by_placeholder("选择地区").click()
            self.page.get_by_text("四川省", exact=True).click()
            self.page.get_by_text("成都市", exact=True).click()
            self.page.get_by_text("金牛区", exact=True).click()
            self.page.get_by_role("button", name="查询").click()
            with self.page.expect_download() as download_info:
                self.page.get_by_role("button", name="导出").click()
            download = download_info.value
            download.save_as(save_path)
            # print(f'已在线下载：{save_path}')
            return True
        except Exception as e:
            # print(f'下载失败：{e}')
            return False

    # 获取指定xpath下一级的所有xpath并返回字典
    def get_child_xpaths(self, xpath, sub_element='*'):
        """
        获取指定xpath下一级的所有直接子元素的xpath，并返回包含文本内容的字典

        参数:
            xpath (str): 父元素的xpath
            sub_element(str):下级元素的类别，例如li，如果不填，默认把所有的*都算作进去

        返回:
            dict: 包含子元素xpath及其文本内容的字典
        """
        try:
            # 查找父元素
            parent_element = self.page.locator(xpath)

            # 获取子元素数量
            child_count = parent_element.locator(sub_element).count()
            # print(child_count)

            # 存储结果的字典
            child_xpaths = {}

            # 遍历每个子元素

            for i in range(child_count):
                # 构建子元素的xpath
                child_xpath = f"{xpath}/*[{i + 1}]"

                # 获取子元素的文本内容
                try:
                    text_content = self.page.locator(child_xpath).text_content(timeout=1000).strip()
                except Exception:
                    text_content = ""

                # 添加到结果字典
                child_xpaths[f'sub_element_{i + 1}'] = child_xpath
                # child_xpaths[child_xpath] = text_content

            return child_xpaths

        except Exception as e:
            print(f"获取子元素XPath失败: {e}")
            return {}

    # 获取指定xpath的父元素xpath
    def get_parent_xpath(self, xpath):
        """
        获取指定xpath的父元素的xpath

        参数:
            xpath (str): 子元素的xpath

        返回:
            str: 父元素的xpath
        """
        try:
            # 如果已经是根节点，返回自身
            if xpath == '/' or xpath == '/*':
                return xpath

            # 处理以//开头的相对路径
            if xpath.startswith('//'):
                # 移除最后一个斜杠后的所有内容
                last_slash_index = xpath.rfind('/')
                if last_slash_index > 1:  # 确保不是第一个斜杠
                    return xpath[:last_slash_index] or '//'
                else:
                    return '//'

            # 处理绝对路径
            else:
                # 移除最后一个斜杠后的所有内容
                last_slash_index = xpath.rfind('/')
                if last_slash_index > 0:
                    parent_path = xpath[:last_slash_index]
                    return parent_path or '/'
                else:
                    return '/'

        except Exception as e:
            print(f"获取父元素XPath失败: {e}")
            return None
